#!/bin/bash -e
#
#   Neutron3529's Unity Game Plugin
#   Copyright (C) 2022 Neutron3529
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as
#   published by the Free Software Foundation, either version 3 of the
#   License, or (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
############################################################################
#
#   * compile instructions: put this file and `utils.cs` in `steamapps`
#   * folder, open a terminal in the same folder, and execute:
#   *
#   * ```
#   *     chmod +x ${file}.cs
#   *     ./${file}.cs
#   * ```
#   *
#   * then the mod will be compiled automatically.
#   *
#   * Here we wrote a shebang like file, which is correct
#   * in my computer (Manjaro XFCE), if such script do not work
#   * in your computer, you could just try the instructions below :

export GAME_NAME="TheWorldOfKongFu"                                # might modify if the name mismatch.
export GAME_DIR="TWOKF"                                # might be modified, but "$GAME_NAME" cover most of the cases.

export FILE_NAME="$0"
export ASSEMBLY="Assembly-CSharp"                           # might be modified
export PLUGIN_ID="BaseResourceManager"                        # should be modified
export NAMESPACE_ID="BaseResourceManager"                     # should be modified
export GAME_BASE_DIR="common/$GAME_DIR"                     # should modify GAME_DIR instead since GAME_DIR == GAME_NAME is almost always true.

export IFS=$'\n' # to disable the annoying space.
export DOTNET="dotnet" # the location of the DOTNET executable file.
[ -z "$DOTNET_CSC_DLL" ] && export DOTNET_CSC_DLL=`\ls /usr/share/dotnet/sdk/*/Roslyn/bincore/csc.dll` # In manjaro, the csc.dll is located in /usr/share/dotnet/sdk/*/Roslyn/bincore/csc.dll

__MODE_VERBOSE=99 # is the line number of "#define VERBOSE", may be modified
__MODE_DEBUG__=$((__MODE_VERBOSE+1))
__MODE_RELEASE=$((__MODE_DEBUG__+1))

case $1 in
    V)       _MODE__SELECT_=$__MODE_VERBOSE     ;;
    v)       _MODE__SELECT_=$__MODE_VERBOSE     ;;
    VERBOSE) _MODE__SELECT_=$__MODE_VERBOSE     ;;
    verbose) _MODE__SELECT_=$__MODE_VERBOSE     ;;
    D)       _MODE__SELECT_=$__MODE_DEBUG__     ;;
    d)       _MODE__SELECT_=$__MODE_DEBUG__     ;;
    DEBUG)   _MODE__SELECT_=$__MODE_DEBUG__     ;;
    debug)   _MODE__SELECT_=$__MODE_DEBUG__     ;;
    *)       _MODE__SELECT_=$__MODE_RELEASE     ;;
esac

( yes "" | head -n $_MODE__SELECT_ | head -n-1  ; tail $FILE_NAME -n+$_MODE__SELECT_ ) | sed s/%%NAMESPACE_ID%%/${NAMESPACE_ID}/g | sed s/%%PLUGIN_ID%%/${PLUGIN_ID}/g | $DOTNET $DOTNET_CSC_DLL -nologo -t:library \
  -r:"${GAME_BASE_DIR}/BepInEx/core/BepInEx.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/core/0Harmony.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/core/BepInEx.Harmony.dll" \
  `[ -e "${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/netstandard.dll" ] && echo "-r:\"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/netstandard.dll\""` \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/System.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/System.Core.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.AIModule.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.AssetBundleModule.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.CoreModule.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.UI.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/mscorlib.dll" \
  $(for i in "${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/$ASSEMBLY"*.dll ; do echo -e "-r:\"$i\"\n" ; done) \
  -out:"${GAME_BASE_DIR}/BepInEx/plugins/${FILE_NAME%.*}".dll \
  -optimize `[ "$_MODE__SELECT_" == "$__MODE_DEBUG__" ] && echo -debug` \
  - && rm -f "${GAME_BASE_DIR}/BepInEx/config/${PLUGIN_ID}.cfg";

if [ -n "$2" ]; then
    git add ${FILE_NAME}
    case $2 in
        R) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        r) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        RANDOM) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        random) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        U) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        u) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        UPLOAD) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        upload) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        *) git commit -am "$2" ;;
    esac
    git push
fi
exit

#define VERBOSE // the line of __MODE_VERBOSE
#define DEBUG



using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;

using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
using UnityEngine.UI;

namespace %%NAMESPACE_ID%%
{
    [BepInPlugin("%%PLUGIN_ID%%", "%%NAMESPACE_ID%%", "0.1.1")]
    public class %%PLUGIN_ID%% : BaseUnityPlugin {
        public static string current_csv="dummy.csv";
        public static string dump_dir="BRM.Modder.csv";
        public static string mod_dir="BRM.csvMod";
        public static string asset_dir="BRM.asset"; // not for now.
        public static bool alert_overwrite=dump_dir.Length!=0;
        public static bool abort_on_error=true;
        public static List<AssetBundle> asset_list=new List<AssetBundle>();
        public static Dictionary<string,int> asset_dict=new Dictionary<string,int>();
        public Harmony harmony;
        void Awake() {
            harmony=new Harmony("%%PLUGIN_ID%%");
            Logger.LogInfo("此Mod使用AGPL-v3许可发布，如果你使用了这里的代码，请按照相同许可发布你修改后的mod。");
#if DEBUG
            logger=Logger.LogInfo;
            loggeri=(i,s) =>{logger(s);return i;};
            logger("开始注入");
#endif
            asset_dict.Clear();
            asset_list.Clear();
            logger("清除asset以防万一");
            AssetBundle ab=AssetBundle.LoadFromFile("BRM.asset/data.unity3d");
            if(ab==null){logger("ab==null, failed to patch");} else {
                asset_list.Add(ab);
                asset_dict.Add("Datas/gang_b06",0);
            }
            harmony.PatchAll(typeof(ResourceLoad));
        }
// class UnityEngine.Object UnityEngine.Resources::Load(string, class [mscorlib]System.Type)
        [HarmonyPatch(typeof(UnityEngine.Resources),"Load",new Type[]{typeof(string),typeof(Type)})]
        class ResourceLoad {
            public static bool Prefix(string path,Type systemTypeInstance,UnityEngine.Object __result) {
                if (asset_dict.ContainsKey(path)) {
                    logger("loading.. "+path+"idx="+asset_dict[path]);
                    __result=asset_list[asset_dict[path]].LoadAsset(path,systemTypeInstance);
                    if(__result==null)logger("loading failed");
                    return __result==null;
                } else {
                    return true;
                }
            }
        }
        void Start() {
            mod_dir=Config.Bind("config", "mod_dir", mod_dir, "csv mod存放路径").Value;
            alert_overwrite=Config.Bind("config", "alert_overwrite", alert_overwrite, "csv覆盖数据时输出警告信息").Value;
            abort_on_error=Config.Bind("config", "abort_on_error", abort_on_error, "当mod不符合载入策略（如，使用id修改id会重复的游戏数据）时禁止mod载入").Value;
            var dump_bind=Config.Bind("config", "dump", dump_dir, "获取游戏内部csv数据（不写Mod的话，不必打开此选项）");
            dump_dir=dump_bind.Value;
            if (mod_dir.Length+dump_dir.Length > 0){
                harmony.PatchAll(typeof(DumpCsv_Load));
                logger("Waring：此Mod使用全局变量记录当前load csv的参数，如果游戏制作组使用多线程，此mod的注入会因为参数错误而失败。");
                logger("但考虑到我真的没见过哪个制作组把多数情况下只需要执行一次load函数改成多线程，理论上讲，mod可以撑过很多次游戏更新。");
            }
            if(mod_dir.Length>0){
                if(!Directory.Exists(mod_dir))Directory.CreateDirectory(mod_dir);
                harmony.PatchAll(typeof(CsvParser2Parse_post));
                logger("已开启基于%%PLUGIN_ID%%的mod。");
            }
            if(dump_dir.Length>0){
                if(!Directory.Exists(dump_dir)) {
                    Directory.CreateDirectory(dump_dir);
                    harmony.PatchAll(typeof(CsvParser2Parse));
                    dump_bind.Value="";
                    logger("获取游戏内部csv数据-patched");
                } else {
                    logger("检测到mod文件夹存在，为了ssd寿命着想，程序将不会自动dump游戏内部的csv数据");
                    logger("如果你的确需要更新csv数据，请删除或者重命名老文件夹");
                    logger("你也可以将.cfg文件里面的dump_dir设置为\"\"，来禁止这个提示。");
                }
            }
            //root.GetDirectories();
            logger("基础资源管理-注入完成。");
        }
        [HarmonyPatch(typeof(CsvParser2),"Parse",new Type[]{typeof(string)})]
        class CsvParser2Parse_post {
            static string [][] Postfix(string [][] result, string input)
            {
                string curr=current_csv+"-"+(Crc64.Compute(System.Text.Encoding.UTF8.GetBytes(input.Split('\n')[0]))).ToString("X")+".csv";

                result=Utils.Replace_exact(result,curr);
                result=Utils.Replace_idx(result,curr);

                return result;
            }
        }
        [HarmonyPatch(typeof(CsvParser2),"Parse",new Type[]{typeof(string)})]
        class CsvParser2Parse {
            static void Prefix(string input)
            {
                File.WriteAllText(Path.Combine(dump_dir,current_csv+"-"+(Crc64.Compute(System.Text.Encoding.UTF8.GetBytes(input.Split('\n')[0]))).ToString("X")+".csv"),input);
            }
        }
        class DumpCsv_Load {
            static void Prefix(MethodBase __originalMethod) {
                current_csv=__originalMethod.DeclaringType.ToString();
            }
            static void Postfix(MethodBase __originalMethod) {
                current_csv="dummy.csv";
            }
            static IEnumerable<MethodBase> TargetMethods(){
                Type[] t=typeof(SharedData).Assembly.GetTypes();
                foreach(Type ty in t){
                    MethodInfo[] m=ty.GetMethods();
                    foreach(MethodInfo i in m)if(i.Name=="Load"){
                        logger("准备注入类别"+ty.ToString()+"的Load方法");
                        yield return i;
                    }
                }
            }
        }
#if DEBUG
        public static Func<int,string,int> loggeri;
        public static Action<string> logger;
#else
        public static void logger(string s){}
#endif

        public static class Utils{
            public static string [][] Replace_idx(string [][] result,string curr){
                bool should_return=true;
                string beiguo_mod="";
                foreach(var dir in (new DirectoryInfo(mod_dir)).GetDirectories()){
                    if (dir.GetFiles(curr).Length>0 ){
                        logger("搜索到Mod "+dir.Name+"中存在"+curr+"的id补丁");
                        should_return=false;
                        break;
                    }
                }
                if(should_return){
                    return result;
                }
                Dictionary<string,int> idx=new Dictionary<string,int>();
                for(int i=0;i<result.Length;i++){
                    if(!idx.TryAdd(result[i][0],i)){
                        logger("Error: 文件"+curr+"行"+(i+1).ToString()+"的id "+result[i][0]+"与第"+(idx[result[i][0]]+1).ToString()+"行定义的id重复！这可能导致mod:"+beiguo_mod+" 的生效方式与Mod作者设想的不同");
                    }
                }
                List<string[]> str=result.ToList();

                foreach(var dir in (new DirectoryInfo(mod_dir)).GetDirectories()){
                    foreach( var file in dir.GetFiles(curr) ){
                        var res=new CsvParser().Parse(file.OpenText());
                        for(int i=1;i<res.Length;i++){
                            if(idx.TryAdd(res[i][0],str.Count)){
                                str.Add(res[i]);
                            }else{
                                if(alert_overwrite)logger("Warning: Mod"+dir.Name+" id "+res[i][0]+" 重复，文件"+curr+"行"+i.ToString()+"，按默认策略，进行覆盖");
                                str[idx[res[i][0]]]=res[i];
                            }
                        }
                    }
                }
                return str.ToArray();
            }
            public static string [][] Replace_exact(string [][] result,string curr){
                bool should_return=true;
                string beiguo_mod="";
                foreach(var dir in (new DirectoryInfo(mod_dir)).GetDirectories()){
                    if (dir.GetFiles(curr+".from.csv").Length>0 ){
                        logger("搜索到Mod "+dir.Name+"中存在"+curr+"的from-to补丁");
                        should_return=false;
                        break;
                    }
                }
                if(should_return){
                    return result;
                }
                Dictionary<string,int> idx=new Dictionary<string,int>();
                for(int i=0;i<result.Length;i++){
                    if(!idx.TryAdd(String.Join(",&|*|&,",result[i]),i)){
                        logger("Error: 文件"+curr+"行"+(i+1).ToString()+"与第"+(idx[String.Join(",&|*|&,",result[i])]+1).ToString()+"行完全一致！这可能导致mod:"+beiguo_mod+" 的生效方式与Mod作者设想的不同");
                        if(abort_on_error){
                            logger("按abort_on_error设定策略，停止对fromto Mod的进一步处理，所有以"+curr+"开头的mod将不再生效。");
                            return result;
                        }
                    }
                }
                List<string[]> str=result.ToList();

                foreach(var dir in (new DirectoryInfo(mod_dir)).GetDirectories()){
                    foreach( var file1 in dir.GetFiles(curr+".from.csv") ){
                        foreach( var file2 in dir.GetFiles(curr+".to.csv") ){
                            var from=new CsvParser().Parse(file1.OpenText());
                            var to=new CsvParser().Parse(file2.OpenText());
                            int i=1;
                            for(;i<from.Length;i++){
                                int curridx;
                                {
                                    var x=idx.TryGetValue(String.Join(",&|*|&,",to[i]),out curridx);
                                    logger("idx="+curridx+"x="+x);
                                }
                                if((!idx.TryGetValue(String.Join(",&|*|&,",to[i]),out curridx)) && idx.TryGetValue(String.Join(",&|*|&,",from[i]),out curridx)){
                                    str[curridx]=to[i];
                                    idx.Remove(String.Join(",&|*|&,",from[i]));
                                    idx.Add(String.Join(",&|*|&,",to[i]),curridx);
                                } else {
                                    if(idx.TryGetValue(String.Join(",&|*|&,",from[i]),out curridx)){
                                        logger("Warning: to中条目(line="+String.Join(",",to[i])+")已存在，可能是其他mod进行了覆写，或者游戏进行了更新");
                                    } else {
                                        logger("Warning: from中条目(line="+String.Join(",",from[i])+")不存在，可能是其他mod进行了覆写，或者游戏进行了更新");
                                    }
                                }
                            }
                            if(from.Length<to.Length)logger("mod "+dir.Name+"中存在无条件新增条目，现进行无条件新增");
                            for(;i<to.Length;i++){
                                int curridx;
                                if(!idx.TryGetValue(String.Join(",&|*|&,",to[i]),out curridx)){
                                    idx.Add(String.Join(",&|*|&,",to[i]),str.Count);
                                    str.Add(to[i]);
                                } else {
                                    logger("Warning: to中条目(line="+String.Join(",",to[i])+")已存在，可能是其他mod进行了覆写，或者游戏进行了更新");
                                }
                            }
                        }
                    }
                }
                return str.ToArray();
            }
        }
        public static class Crc64 // https://gist.github.com/maxpert/c544fade7be86270021ef8799cff73f6
        {
            private static readonly ulong[] Table = {
                0x0000000000000000, 0x7ad870c830358979,
                0xf5b0e190606b12f2, 0x8f689158505e9b8b,
                0xc038e5739841b68f, 0xbae095bba8743ff6,
                0x358804e3f82aa47d, 0x4f50742bc81f2d04,
                0xab28ecb46814fe75, 0xd1f09c7c5821770c,
                0x5e980d24087fec87, 0x24407dec384a65fe,
                0x6b1009c7f05548fa, 0x11c8790fc060c183,
                0x9ea0e857903e5a08, 0xe478989fa00bd371,
                0x7d08ff3b88be6f81, 0x07d08ff3b88be6f8,
                0x88b81eabe8d57d73, 0xf2606e63d8e0f40a,
                0xbd301a4810ffd90e, 0xc7e86a8020ca5077,
                0x4880fbd87094cbfc, 0x32588b1040a14285,
                0xd620138fe0aa91f4, 0xacf86347d09f188d,
                0x2390f21f80c18306, 0x594882d7b0f40a7f,
                0x1618f6fc78eb277b, 0x6cc0863448deae02,
                0xe3a8176c18803589, 0x997067a428b5bcf0,
                0xfa11fe77117cdf02, 0x80c98ebf2149567b,
                0x0fa11fe77117cdf0, 0x75796f2f41224489,
                0x3a291b04893d698d, 0x40f16bccb908e0f4,
                0xcf99fa94e9567b7f, 0xb5418a5cd963f206,
                0x513912c379682177, 0x2be1620b495da80e,
                0xa489f35319033385, 0xde51839b2936bafc,
                0x9101f7b0e12997f8, 0xebd98778d11c1e81,
                0x64b116208142850a, 0x1e6966e8b1770c73,
                0x8719014c99c2b083, 0xfdc17184a9f739fa,
                0x72a9e0dcf9a9a271, 0x08719014c99c2b08,
                0x4721e43f0183060c, 0x3df994f731b68f75,
                0xb29105af61e814fe, 0xc849756751dd9d87,
                0x2c31edf8f1d64ef6, 0x56e99d30c1e3c78f,
                0xd9810c6891bd5c04, 0xa3597ca0a188d57d,
                0xec09088b6997f879, 0x96d1784359a27100,
                0x19b9e91b09fcea8b, 0x636199d339c963f2,
                0xdf7adabd7a6e2d6f, 0xa5a2aa754a5ba416,
                0x2aca3b2d1a053f9d, 0x50124be52a30b6e4,
                0x1f423fcee22f9be0, 0x659a4f06d21a1299,
                0xeaf2de5e82448912, 0x902aae96b271006b,
                0x74523609127ad31a, 0x0e8a46c1224f5a63,
                0x81e2d7997211c1e8, 0xfb3aa75142244891,
                0xb46ad37a8a3b6595, 0xceb2a3b2ba0eecec,
                0x41da32eaea507767, 0x3b024222da65fe1e,
                0xa2722586f2d042ee, 0xd8aa554ec2e5cb97,
                0x57c2c41692bb501c, 0x2d1ab4dea28ed965,
                0x624ac0f56a91f461, 0x1892b03d5aa47d18,
                0x97fa21650afae693, 0xed2251ad3acf6fea,
                0x095ac9329ac4bc9b, 0x7382b9faaaf135e2,
                0xfcea28a2faafae69, 0x8632586aca9a2710,
                0xc9622c4102850a14, 0xb3ba5c8932b0836d,
                0x3cd2cdd162ee18e6, 0x460abd1952db919f,
                0x256b24ca6b12f26d, 0x5fb354025b277b14,
                0xd0dbc55a0b79e09f, 0xaa03b5923b4c69e6,
                0xe553c1b9f35344e2, 0x9f8bb171c366cd9b,
                0x10e3202993385610, 0x6a3b50e1a30ddf69,
                0x8e43c87e03060c18, 0xf49bb8b633338561,
                0x7bf329ee636d1eea, 0x012b592653589793,
                0x4e7b2d0d9b47ba97, 0x34a35dc5ab7233ee,
                0xbbcbcc9dfb2ca865, 0xc113bc55cb19211c,
                0x5863dbf1e3ac9dec, 0x22bbab39d3991495,
                0xadd33a6183c78f1e, 0xd70b4aa9b3f20667,
                0x985b3e827bed2b63, 0xe2834e4a4bd8a21a,
                0x6debdf121b863991, 0x1733afda2bb3b0e8,
                0xf34b37458bb86399, 0x8993478dbb8deae0,
                0x06fbd6d5ebd3716b, 0x7c23a61ddbe6f812,
                0x3373d23613f9d516, 0x49aba2fe23cc5c6f,
                0xc6c333a67392c7e4, 0xbc1b436e43a74e9d,
                0x95ac9329ac4bc9b5, 0xef74e3e19c7e40cc,
                0x601c72b9cc20db47, 0x1ac40271fc15523e,
                0x5594765a340a7f3a, 0x2f4c0692043ff643,
                0xa02497ca54616dc8, 0xdafce7026454e4b1,
                0x3e847f9dc45f37c0, 0x445c0f55f46abeb9,
                0xcb349e0da4342532, 0xb1eceec59401ac4b,
                0xfebc9aee5c1e814f, 0x8464ea266c2b0836,
                0x0b0c7b7e3c7593bd, 0x71d40bb60c401ac4,
                0xe8a46c1224f5a634, 0x927c1cda14c02f4d,
                0x1d148d82449eb4c6, 0x67ccfd4a74ab3dbf,
                0x289c8961bcb410bb, 0x5244f9a98c8199c2,
                0xdd2c68f1dcdf0249, 0xa7f41839ecea8b30,
                0x438c80a64ce15841, 0x3954f06e7cd4d138,
                0xb63c61362c8a4ab3, 0xcce411fe1cbfc3ca,
                0x83b465d5d4a0eece, 0xf96c151de49567b7,
                0x76048445b4cbfc3c, 0x0cdcf48d84fe7545,
                0x6fbd6d5ebd3716b7, 0x15651d968d029fce,
                0x9a0d8ccedd5c0445, 0xe0d5fc06ed698d3c,
                0xaf85882d2576a038, 0xd55df8e515432941,
                0x5a3569bd451db2ca, 0x20ed197575283bb3,
                0xc49581ead523e8c2, 0xbe4df122e51661bb,
                0x3125607ab548fa30, 0x4bfd10b2857d7349,
                0x04ad64994d625e4d, 0x7e7514517d57d734,
                0xf11d85092d094cbf, 0x8bc5f5c11d3cc5c6,
                0x12b5926535897936, 0x686de2ad05bcf04f,
                0xe70573f555e26bc4, 0x9ddd033d65d7e2bd,
                0xd28d7716adc8cfb9, 0xa85507de9dfd46c0,
                0x273d9686cda3dd4b, 0x5de5e64efd965432,
                0xb99d7ed15d9d8743, 0xc3450e196da80e3a,
                0x4c2d9f413df695b1, 0x36f5ef890dc31cc8,
                0x79a59ba2c5dc31cc, 0x037deb6af5e9b8b5,
                0x8c157a32a5b7233e, 0xf6cd0afa9582aa47,
                0x4ad64994d625e4da, 0x300e395ce6106da3,
                0xbf66a804b64ef628, 0xc5bed8cc867b7f51,
                0x8aeeace74e645255, 0xf036dc2f7e51db2c,
                0x7f5e4d772e0f40a7, 0x05863dbf1e3ac9de,
                0xe1fea520be311aaf, 0x9b26d5e88e0493d6,
                0x144e44b0de5a085d, 0x6e963478ee6f8124,
                0x21c640532670ac20, 0x5b1e309b16452559,
                0xd476a1c3461bbed2, 0xaeaed10b762e37ab,
                0x37deb6af5e9b8b5b, 0x4d06c6676eae0222,
                0xc26e573f3ef099a9, 0xb8b627f70ec510d0,
                0xf7e653dcc6da3dd4, 0x8d3e2314f6efb4ad,
                0x0256b24ca6b12f26, 0x788ec2849684a65f,
                0x9cf65a1b368f752e, 0xe62e2ad306bafc57,
                0x6946bb8b56e467dc, 0x139ecb4366d1eea5,
                0x5ccebf68aecec3a1, 0x2616cfa09efb4ad8,
                0xa97e5ef8cea5d153, 0xd3a62e30fe90582a,
                0xb0c7b7e3c7593bd8, 0xca1fc72bf76cb2a1,
                0x45775673a732292a, 0x3faf26bb9707a053,
                0x70ff52905f188d57, 0x0a2722586f2d042e,
                0x854fb3003f739fa5, 0xff97c3c80f4616dc,
                0x1bef5b57af4dc5ad, 0x61372b9f9f784cd4,
                0xee5fbac7cf26d75f, 0x9487ca0fff135e26,
                0xdbd7be24370c7322, 0xa10fceec0739fa5b,
                0x2e675fb4576761d0, 0x54bf2f7c6752e8a9,
                0xcdcf48d84fe75459, 0xb71738107fd2dd20,
                0x387fa9482f8c46ab, 0x42a7d9801fb9cfd2,
                0x0df7adabd7a6e2d6, 0x772fdd63e7936baf,
                0xf8474c3bb7cdf024, 0x829f3cf387f8795d,
                0x66e7a46c27f3aa2c, 0x1c3fd4a417c62355,
                0x935745fc4798b8de, 0xe98f353477ad31a7,
                0xa6df411fbfb21ca3, 0xdc0731d78f8795da,
                0x536fa08fdfd90e51, 0x29b7d047efec8728,
            };

            public static ulong Compute(byte[] s, ulong crc = 0)
            {
                for (int j = 0; j < s.Length; j++)
                {
                    crc = Crc64.Table[(byte)(crc ^ s[j])] ^ (crc >> 8);
                }

                return crc;
            }
        }
    }
}


